Step 0: Prepare covariates and input files

IDs <- fread("~/genotype_qc/TERRE_QC/all_imputed_r2_30_rsid_hard_call.fam")[, .(FID = V1, IID = V2)]
prsice_cov <- fread("prsice_cov_and_status_mvalues.txt")
prsice_cov <- prsice_cov[match(IDs$IID,prsice_cov$IID)]
all(IDs$IID ==prsice_cov$IID)
[1] NA
covariate <- cbind(IDs, prsice_cov[,-c(16,17,18)])

PD <- cbind(IDs,prsice_cov[,16])

head(covariate)
head(PD)
fwrite(na.omit(PD), "TERRE.pheno", sep = "\t")
fwrite(na.omit(covariate), "TERRE.covariate", sep = "\t")
covariate

Step 1: Run PRSice-2 on Nalls et al 2019 Sumstats

Rscript /home1/NEURO/casazza/PRSice.R \
    --prsice /home1/NEURO/casazza/PRSice_linux\
    --base /home1/NEURO/casazza/nalls_PD.QC.gz\
    --base-info INFO:0.8 \
    --base-maf MAF:0.01 \
    --cov TERRE.covariate \
    --binary-target T\
    --beta  \
    --ld /home1/NEURO/casazza/1000G_plink/EUR_phase3  \
    --out TERRE_PRSice \
    -q 5\
    --all-score\
    --pheno TERRE.pheno \
    --snp SNP \
    --stat b \
    --pvalue p\
    --target /home1/NEURO/casazza/genotype_qc/TERRE_QC/all_imputed_r2_30_rsid_hard_call \
    --thread 32

Step 2: Evaluate output

include_graphics("prsice_images/TERRE_PRSice_BARPLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_HIGH-RES_PLOT_2022-06-30.png")

include_graphics("prsice_images/TERRE_PRSice_QUANTILES_PLOT_2022-06-30.png")


include_graphics("prsice_images/TERRE_PRSice_nalls_male_BARPLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_HIGH-RES_PLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_male_QUANTILES_PLOT_2022-10-04.png")


include_graphics("prsice_images/TERRE_PRSice_nalls_female_BARPLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_HIGH-RES_PLOT_2022-10-04.png")

include_graphics("prsice_images/TERRE_PRSice_nalls_female_QUANTILES_PLOT_2022-10-04.png")

Plotting PRSice Data on my own

library(ggnewscale)
prsice_male_meta <- fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.prsice")
ggplot(prsice_male_meta[Threshold <= 0.5], aes(Threshold, Num_SNP, color = -log10(P))) +
  geom_point() +
  scale_y_continuous(breaks = c(seq(0, 1e5, 2.5e4), seq(2e5, 6e5, 1e5))) +
  theme_minimal()


prsice_female_meta <- fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.prsice")
ggplot(prsice_female_meta[Threshold <= 0.5], aes(Threshold, Num_SNP, color = -log10(P))) +
  geom_point() +
  scale_y_continuous(breaks = c(seq(0, 1e5, 2.5e4), seq(2e5, 6e5, 1e5))) +
  theme_minimal()


prsice_meta <- fread("prsice_data/TERRE_PRSice.prsice")
ggplot(mapping = aes(Threshold, R2, color = -log10(P))) +
  geom_point(data = prsice_female_meta, size = 1) +
  scale_color_gradient(low = "lightpink4", high = "lightpink") +
  labs(color = bquote("Female log"["10"] ~ "(P)")) +
  new_scale_color() +
  geom_point(data = prsice_male_meta, size = 1, aes(color = -log10(P))) +
  scale_color_gradient(low = "lightblue4", high = "lightblue") +
  labs(y = bquote("R"^2), x = "GWAS P-Value Threshold", color = bquote("Male -log"["10"] ~ "(P)")) +
  theme_minimal() +
  theme(legend.position = "top")

ggplot(mapping = aes(Threshold, R2, color = -log10(P))) +
  geom_point(data = prsice_female_meta, size = 1) +
  scale_color_gradient(low = "lightpink4", high = "lightpink",guide = guide_colorbar(order=3)) +
  labs(color = bquote("Female -log"["10"] ~ "(P)")) +
  new_scale_color() +
  geom_point(data = prsice_male_meta, size = 1, aes(color = -log10(P))) +
  scale_color_gradient(low = "lightblue4", high = "lightblue",guide = guide_colorbar(order=2)) +
  labs(color = bquote("Male -log"["10"] ~ "(P)")) +
  new_scale_color() +
  geom_point(data = prsice_meta, size = 1, aes(color = -log10(P))) +
  scale_color_gradient(low = "gray40", high = "gray80",guide = guide_colorbar(order=1)) +
  labs(y = bquote("R"^2), x = "GWAS P-Value Threshold", color = bquote("Cross-sex -log"["10"] ~ "(P)")) +
  theme_minimal() +
  theme(legend.position = "top",legend.title = element_text(size=7))

Step 3 run linear model at different thresholds for SNP inclusion

This is updated to recently processed DNAm Data 20 outliers in DNAm removed:

load("/home1/NEURO/SHARE_DECIPHER/processed_DNAm_data/2022/TERRE_processed_2022/1-TERRE_RG_filtered.RData") #PD_RG_filtered
# Assign genotyping ID to data
original_covars <- fread("/home1/NEURO/SHARE_DECIPHER/terre_meta_master.csv")[, .(patient, IID = gsub("_PAE.*", "", IID))]
betas_combat <- minfi::getBeta(PD_RG_filtered)
colnames(betas_combat) <- original_covars$IID[match(colnames(betas_combat), original_covars$patient)]
betas_combat <- betas_combat[, colnames(betas_combat) %in% covariate$IID]

Let’s check how the data looks for the first 5 subjects:

ggplot(betas_combat[, 1:5] %>% as.data.table(keep.rownames = T) %>% melt(id.vars = "rn", value.name = "betas", variable.name = "subject"), aes(betas, color = subject))+
  geom_density()

Match DNA, PRS, and metadata @TODO fix this after update of PRS etc.

prsice_best <- fread("prsice_data/TERRE_PRSice.best")[match(colnames(betas_combat), IID,nomatch=0),.(best=PRS)]
prsice_all <- cbind(
  fread("prsice_data/TERRE_PRSice.all_score")[match(colnames(betas_combat), IID,nomatch=0), .(FID, IID, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)],
  prsice_best
)
covariate <- covariate[match(colnames(betas_combat), IID)]
all(covariate$IID == colnames(betas_combat))
[1] TRUE
all(covariate$IID == prsice_all$IID)
[1] TRUE
covariate_male <- covariate[sex == 1] %>% select(-sex)
betas_male <- betas_combat[, covariate_male$IID]
prsice_male_best <- fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.best")[match(colnames(betas_male), IID,nomatch=0),.(best=PRS)]
prsice_male_all <- cbind(
  fread("prsice_nalls_male_data/TERRE_PRSice_nalls_male.all_score")[match(colnames(betas_male), IID,nomatch=0), .(FID, IID, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)],
  prsice_male_best
)
covariate_male <- covariate_male[match(colnames(betas_male), IID,nomatch=0)]
all(covariate_male$IID == colnames(betas_male))
[1] TRUE
all(covariate_male$IID == prsice_male_all$IID)
[1] TRUE
prsice_female_best <- fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.best")
covariate_female <- covariate[sex == 0] %>% select(-sex) %>% filter(IID %in% prsice_female_best$IID)
betas_female <- betas_combat[, covariate_female$IID]
prsice_female_best <- prsice_female_best[match(colnames(betas_female), IID,nomatch=0),.(best=PRS)]
prsice_female_all <- cbind(
  fread("prsice_nalls_female_data/TERRE_PRSice_nalls_female.all_score")[match(colnames(betas_female), IID,nomatch=0), .(FID, IID, `Pt_5e-08`, `Pt_5.005e-05`, `Pt_0.00010005`, `Pt_0.00100005`, `Pt_0.0101501`, `Pt_0.1`, `Pt_0.2`, `Pt_0.3`, `Pt_0.4`, `Pt_0.5`, `Pt_1`)],
  prsice_female_best
)
covariate_female <- covariate_female[match(colnames(betas_female), IID,nomatch=0)]
all(covariate_female$IID == colnames(betas_female))
[1] TRUE
all(covariate_female$IID == prsice_female_all$IID)
[1] TRUE

Run limma

mvalues <- lumi::beta2m(betas_combat)
prs_mat <- prsice_all[, -c(1, 2)]
cov_mat <- covariate[, -c(1, 2)]

mvalues_male <- lumi::beta2m(betas_male)
prs_mat_male <- prsice_male_all[, -c(1, 2)]
cov_mat_male <- covariate_male[, -c(1, 2)]

mvalues_female <- lumi::beta2m(betas_female)
prs_mat_female <- prsice_female_all[, -c(1, 2)]
cov_mat_female <- covariate_female[, -c(1, 2)]
registerDoParallel(ncol(prs_mat) / 4)
hits <- foreach(prs_thresh = colnames(prs_mat)) %dopar% {
  design_prs <- model.matrix(~., data = cbind(prs_mat[, ..prs_thresh], cov_mat))
  prs_fit <- lmFit(mvalues, design_prs)
  prs_fit <- eBayes(prs_fit)
  topTable(prs_fit, coef = 2, adjust.method = "bonf", p.value = 0.05, number = Inf, genelist = rownames(mvalues))
}

Plotting EWAS vs Threshold Experiment by Sex

to_plot <- rbind(
  hits_by_thresh_bonf[, .(hits = .N, Sex = "Cross-sex"), by = threshold] %>%
    mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0")),
  hits_by_thresh_bonf_male[, .(hits = .N, Sex = "Male"), by = threshold] %>%
    mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0")),
  hits_by_thresh_bonf_female[, .(hits = .N, Sex = "Female"), by = threshold] %>%
    mutate(threshold = recode_factor(threshold, `Pt_0.0219001` = "0.0219", `Pt_5e-08` = "5e-8", `Pt_5.005e-05` = "5e-5", `Pt_0.00010005` = "1e-4", `Pt_0.00100005` = "1e-3", `Pt_0.0101501` = "1e-2", `Pt_0.1` = "0.1", `Pt_0.2` = "0.2", `Pt_0.3` = "0.3", `Pt_0.4` = "0.4", `Pt_0.5` = "0.5", `Pt_1` = "1.0"))
) %>% mutate(Sex = factor(Sex, levels = c("Cross-sex", "Male", "Female")))
plot_pos <- position_dodge(width = 1)
ggplot(to_plot, aes(threshold, hits, fill = Sex, label = hits)) +
  geom_text(position = plot_pos, vjust = -0.25) +
  geom_col(position = plot_pos) +
  labs(x = "GWAS P Value Threshold", y = "EWAS Hits") +
  scale_fill_manual(values = c("grey80", "lightblue", "lightpink")) +
  theme_minimal()

hits_by_thresh_bonf[, .(hits = .N, Sex = "Cross-sex"), by = threshold]
hits_by_thresh_bonf_male[, .(hits = .N), by = threshold]
hits_by_thresh_bonf_female[, .(hits = .N), by = threshold]
display_venn <- function(x, ...) {
  library(VennDiagram)
  grid.newpage()
  venn_object <- venn.diagram(x, filename = NULL, ...)
  grid.draw(venn_object)
}

display_venn(list(`Cross-sex` = hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID, Male = hits_by_thresh_bonf_male[threshold == "Pt_5e-08"]$ID, Female = hits_by_thresh_bonf_female[threshold == "Pt_5e-08"]$ID), fill = c("gray80", "lightblue", "lightpink"))
Loading required package: grid
Loading required package: futile.logger

male_ids <- hits_by_thresh_bonf_male[threshold == "Pt_5e-08"]$ID
cross_ids <- hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID
male_ids[!male_ids %in% cross_ids]
character(0)
get_full_fit <- function(prs_mat,cov_mat,mvalues){
  top_design_prs <- model.matrix(~., data = cbind(prs_mat[, `Pt_5e-08`], cov_mat))
  top_prs_fit <- lmFit(mvalues, top_design_prs)
  top_prs_fit <- eBayes(top_prs_fit)
  top_prs_hits <- topTable(top_prs_fit, coef = 2, adjust.method = "bonf", number = Inf, genelist = rownames(mvalues))
}
top_prs_hits <- get_full_fit(prs_mat,cov_mat,mvalues)
top_male_prs_hits <- get_full_fit(prs_mat_male, cov_mat_male, mvalues_male)
top_female_prs_hits <- get_full_fit(prs_mat_female, cov_mat_female, mvalues_female)
save(list=c("top_prs_hits","top_male_prs_hits","top_female_prs_hits"),file="prs_nalls_cross_w_sex_stratified.RData")
load("prs_nalls_cross_w_sex_stratified.RData")
manifest <- IlluminaHumanMethylationEPICanno.ilm10b4.hg19::Other %>%
  as.data.frame() %>%
  rownames_to_column(var = "name")
prs_annot <- data.table(top_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
prs_annot_male <- data.table(top_male_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
prs_annot_female<- data.table(top_female_prs_hits)[manifest, gene := gsub(";.*", "", UCSC_RefGene_Name), on = c(ID = "name")]
plot_prs_hits <- function(prs_annot,label_color){
  ggplot(prs_annot, aes(logFC, -log10(P.Value))) +
    geom_point() +
    geom_point(
      data = subset(prs_annot, adj.P.Val < 0.05 & abs(logFC) > 0.03),
      color = label_color,
      mapping = aes(logFC, -log10(P.Value))
    ) +
    geom_hline(
      linetype = "dashed",
      yintercept = min(-log10(prs_annot$P.Value[prs_annot$adj.P.Val < 0.05]))
    ) +
    geom_vline(linetype = "dashed", xintercept = 0.03) +
    geom_vline(linetype = "dashed", xintercept = -0.03) +
    geom_text_repel(
      data = prs_annot %>% filter(abs(logFC) > 0.03 & adj.P.Val < 0.05),
      color = "dodgerblue",
      mapping = aes(logFC, -log10(P.Value), label = ifelse(gene != "", gene, ID)),
      size = 3,
      max.overlaps = 20
    ) +
    labs(y = bquote("log"[10] ~ "(P)"), x = quote(Delta ~ "M" ~ Methylation)) +
    theme_minimal()
}

plot_prs_hits(prs_annot,"gray40")

plot_prs_hits(prs_annot_male,"lightblue")

plot_prs_hits(prs_annot_female,"pink")

go enrichment?

library(gprofiler2)
cross_sex <- unique(gsub(";.*","",manifest[manifest$name %in% hits_by_thresh_bonf[threshold == "Pt_5e-08"]$ID,]$UCSC_RefGene_Name))
background <- unique(gsub(";.*","",manifest$UCSC_RefGene_Name))
gost_res <- gost(query=cross_sex,custom_bg = background)
gostplot(gost_res)
gmirror(
  prs_annot_male[,.(SNP=ID,CHR=gsub("chr","",cpg_pos[match(ID,cpg_pos$name),]$chr),POS=cpg_pos[match(ID,cpg_pos$name),]$pos,pvalue=P.Value)],
  prs_annot_female[,.(SNP=ID,CHR=gsub("chr","",cpg_pos[match(ID,cpg_pos$name),]$chr),POS=cpg_pos[match(ID,cpg_pos$name),]$pos,pvalue=P.Value)],
  annotate_snp = c(male_annot_cpg,female_annot_cpg),
  tline =  max(prs_annot_male[adj.P.Val<0.25]$P.Value),
  bline =  max(prs_annot_female[adj.P.Val<0.25]$P.Value),
  highlight_p = c(max(prs_annot_male[adj.P.Val<0.25]$P.Value),max(prs_annot_female[adj.P.Val<0.25]$P.Value)),
  toptitle="Male",
  bottomtitle ="Female",
  highlighter="green",
  background="white"
)
[1] "Saving plot to gmirror.png"
TableGrob (2 x 1) "arrange": 2 grobs

Manhattan plot vs GWAS manhattan plot

library(qqman)

copy_annot <- prs_annot[cpg_pos, on = c(ID = "name")] %>%
  mutate(chr = as.numeric(recode(gsub("chr", "", chr),X="23",Y="24")))
to_plot <- copy_annot[, .(SNP = gene, CHR = chr, BP = pos, P = P.Value, FDR = adj.P.Val)][!is.na(P)]
manhattan(to_plot,
  annotatePval = max(to_plot[FDR < 0.05]$P),
  annotateTop = TRUE,
  genomewideline = min(-log10(to_plot[FDR < 0.05]$P)),
  suggestiveline = FALSE
)
manhattan(to_plot[CHR == 17],
  annotatePval = max(to_plot[FDR < 0.05]$P),
  annotateTop = FALSE,
  genomewideline = min(-log10(to_plot[FDR < 0.05]$P)),
  suggestiveline = FALSE
)
qq(to_plot$P)

DMRs

library(DMRcate)
Loading required package: minfi
Loading required package: BiocGenerics

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:parallel’:

    clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport, clusterMap, parApply, parCapply,
    parLapply, parLapplyLB, parRapply, parSapply, parSapplyLB

The following object is masked from ‘package:limma’:

    plotMA

The following objects are masked from ‘package:dplyr’:

    combine, intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    IQR, mad, sd, var, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq,
    Filter, Find, get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax,
    pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply, union,
    unique, unsplit, which, which.max, which.min

Loading required package: GenomicRanges
Loading required package: stats4
Loading required package: S4Vectors

Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:data.table’:

    first, second

The following objects are masked from ‘package:dplyr’:

    first, rename

The following object is masked from ‘package:tidyr’:

    expand

The following object is masked from ‘package:base’:

    expand.grid

Loading required package: IRanges

Attaching package: ‘IRanges’

The following object is masked from ‘package:data.table’:

    shift

The following objects are masked from ‘package:dplyr’:

    collapse, desc, slice

The following object is masked from ‘package:purrr’:

    reduce

Loading required package: GenomeInfoDb
Loading required package: SummarizedExperiment
Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, see
    'citation("Biobase")', and for packages 'citation("pkgname")'.

Loading required package: DelayedArray
Loading required package: matrixStats

Attaching package: ‘matrixStats’

The following objects are masked from ‘package:Biobase’:

    anyMissing, rowMedians

The following object is masked from ‘package:dplyr’:

    count

Loading required package: BiocParallel

Attaching package: ‘DelayedArray’

The following objects are masked from ‘package:matrixStats’:

    colMaxs, colMins, colRanges, rowMaxs, rowMins, rowRanges

The following object is masked from ‘package:purrr’:

    simplify

The following objects are masked from ‘package:base’:

    aperm, apply, rowsum

Loading required package: Biostrings
Loading required package: XVector

Attaching package: ‘XVector’

The following object is masked from ‘package:purrr’:

    compact


Attaching package: ‘Biostrings’

The following object is masked from ‘package:base’:

    strsplit

Loading required package: bumphunter
Loading required package: locfit
locfit 1.5-9.4   2020-03-24

Attaching package: ‘locfit’

The following object is masked from ‘package:purrr’:

    none

replacing previous import 'minfi::getMeth' by 'bsseq::getMeth' when loading 'DMRcate'
S4_to_dataframe <- function(s4obj) {
  nms <- slotNames(s4obj)
  lst <- lapply(nms, function(nm) slot(s4obj, nm))
  as.data.frame(setNames(lst, nms))
}
run_dmrcate <- function(prs_mat,cov_mat,mvalues){
  design_prs <- model.matrix(~., data = cbind(prs_mat[, `Pt_5e-08`], cov_mat))
  prs_annotated <- cpg.annotate(datatype = "array", object = mvalues, analysis.type = "differential", design = design_prs, coef = 2, what = "M", arraytype = "EPIC", fdr = 0.05)
  prs_dmr_res <- dmrcate(prs_annotated, lambda = 1000, C = 2)
  return(S4_to_dataframe(prs_dmr_res))
}
dmr_cross <- run_dmrcate(prs_mat, cov_mat, mvalues)
Loading required package: IlluminaHumanMethylationEPICanno.ilm10b4.hg19
Your contrast returned 85 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
dmr_males <- run_dmrcate(prs_mat_male,cov_mat_male,mvalues_male)
Your contrast returned 59 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
dmr_female <- run_dmrcate(prs_mat_female,cov_mat_female,mvalues_female)
Your contrast returned 41 individually significant probes; a small but real effect. Consider manually setting the value of pcutoff to return more DMRs, but be warned that doing this increases the risk of Type I errors.
Fitting chr1...
Fitting chr2...
Fitting chr3...
Fitting chr4...
Fitting chr5...
Fitting chr6...
Fitting chr7...
Fitting chr8...
Fitting chr9...
Fitting chr10...
Fitting chr11...
Fitting chr12...
Fitting chr13...
Fitting chr14...
Fitting chr15...
Fitting chr16...
Fitting chr17...
Fitting chr18...
Fitting chr19...
Fitting chr20...
Fitting chr21...
Fitting chr22...
Fitting chrX...
Fitting chrY...
Demarcating regions...
Done!
annotation <- minfi::getAnnotation(IlluminaHumanMethylationEPICanno.ilm10b4.hg19)

Plotting all DMRs

get_dmr_effects <- function(dmr, limma_res,mvalues) {
  dmr_coord <- str_match_all(as.character(dmr), "(chr.*):([0-9]*)-([0-9]*)")[[1]]
  cpgs <- as.data.table(annotation[annotation$chr == dmr_coord[2] & annotation$pos >= as.numeric(dmr_coord[3]) & annotation$pos <= as.numeric(dmr_coord[4]), ])
  res <- limma_res[cpgs,on=c("ID"="Name"),nomatch=0 ]
  dmr_1 <- as.data.frame(res[!is.na(res$logFC), ])
  dmr_methy <- reshape2::melt(lumi::m2beta(mvalues[dmr_1$ID, ]), stringsAsFactors = FALSE)
  to_plot <- merge(dmr_1, dmr_methy, by.x = "ID", by.y = "Var1")
  to_plot$DMR <- dmr
  to_plot
}
get_dmr_res <- function(dmr, limma_res) {
  dmr_coord <- str_match_all(as.character(dmr), "(chr.*):([0-9]*)-([0-9]*)")[[1]]
  cpgs <- annotation[annotation$chr == dmr_coord[2] & annotation$pos >= as.numeric(dmr_coord[3]) & annotation$pos <= as.numeric(dmr_coord[4]), ]
  res <- cbind(cpgs, limma_res[cpgs$Name, ])
  res$DMR <- dmr
  return(res)
}
plot_dmrs <- function(dmr_res,limma_res,prs_mat, mvalues, case_control) {
  to_plot <- rbindlist(lapply(dmr_res$coord, function(dmr) get_dmr_effects(dmr, limma_res,mvalues))) %>%
    mutate(SCORE1_AVG = scale(prs_mat[match(Var2,IDs$IID),`Pt_5e-08`]),PD = PD[match(Var2,IID)]$PD) %>%
    filter(!is.na(SCORE1_AVG))
  for(cur_dmr in unique(to_plot$DMR)){
    cur_plot <- to_plot[DMR == cur_dmr]
    p1 <- ggplot(cur_plot , aes(pos, value, color = SCORE1_AVG)) +
      geom_point() +
      scale_color_gradient(low = rev(case_control)[1], high = rev(case_control)[2]) +
      theme_minimal() +
      labs(title = unique(cur_plot$DMR),x="POS",y=bquote("Methylation"~beta),color = "Normalized PD PRS")+
      theme(axis.text.x = element_text(angle = 90))
    p2 <- ggplot(cur_plot %>% mutate(PD = ifelse(PD == 1, "CASE", "CONTROL")), aes(factor(pos), value, color = PD)) +
      geom_boxplot(position = position_dodge(0.75)) +
      scale_color_manual(values = case_control) +
      theme_minimal() +
      stat_summary(aes(group = PD), fun = mean, geom = "line") +
      labs(title = unique(cur_plot$DMR),x="POS",y=bquote("Methylation"~beta),color = "PD status") +
      theme(axis.text.x = element_text(angle = 90))
    print(p1)
    print(p2)
  }
}

plot_dmrs(dmr_cross, prs_annot, prs_mat,mvalues, rev(c("gray80", "gray40")))

plot_dmrs(dmr_males,prs_annot_male,prs_mat_male, mvalues_male,rev(c("light blue", "lightblue4")))

plot_dmrs(dmr_female, prs_annot_female, prs_mat_female, mvalues_female,rev(c("lightpink", "lightpink4")))

dmr_cross
dmr_males
dmr_female
save(list=c("dmr_cross","dmr_males","dmr_female"),file="prs_dmr_nalls.RData")
LS0tCnRpdGxlOiAiUFJTaWNlMiBEZXZlbG9wbWVudCBvZiByaXNrIHNjb3JlIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShrbml0cikKbGlicmFyeShsaW1tYSkKbGlicmFyeShmb3JlYWNoKQpsaWJyYXJ5KGRvUGFyYWxsZWwpClN5cy5zZXRsb2NhbGUoIkxDX01FU1NBR0VTIiwgImVuX1VTLnV0ZjgiKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBTdGVwIDA6IFByZXBhcmUgY292YXJpYXRlcyBhbmQgaW5wdXQgZmlsZXMKYGBge3J9CklEcyA8LSBmcmVhZCgifi9nZW5vdHlwZV9xYy9URVJSRV9RQy9hbGxfaW1wdXRlZF9yMl8zMF9yc2lkX2hhcmRfY2FsbC5mYW0iKVssIC4oRklEID0gVjEsIElJRCA9IFYyKV0KcHJzaWNlX2NvdiA8LSBmcmVhZCgicHJzaWNlX2Nvdl9hbmRfc3RhdHVzX212YWx1ZXMudHh0IikKcHJzaWNlX2NvdiA8LSBwcnNpY2VfY292W21hdGNoKElEcyRJSUQscHJzaWNlX2NvdiRJSUQpXQphbGwoSURzJElJRCA9PXByc2ljZV9jb3YkSUlEKQpjb3ZhcmlhdGUgPC0gY2JpbmQoSURzLCBwcnNpY2VfY292WywtYygxNiwxNywxOCldKQoKUEQgPC0gY2JpbmQoSURzLHByc2ljZV9jb3ZbLDE2XSkKCmhlYWQoY292YXJpYXRlKQpoZWFkKFBEKQpmd3JpdGUobmEub21pdChQRCksICJURVJSRS5waGVubyIsIHNlcCA9ICJcdCIpCmZ3cml0ZShuYS5vbWl0KGNvdmFyaWF0ZSksICJURVJSRS5jb3ZhcmlhdGUiLCBzZXAgPSAiXHQiKQpgYGAKYGBge3J9CmNvdmFyaWF0ZQpgYGAKCgojIFN0ZXAgMTogUnVuIFBSU2ljZS0yIG9uIE5hbGxzIGV0IGFsIDIwMTkgU3Vtc3RhdHMKYGBge2Jhc2gsZXZhbD1GQUxTRX0KUnNjcmlwdCAvaG9tZTEvTkVVUk8vY2FzYXp6YS9QUlNpY2UuUiBcCiAgICAtLXByc2ljZSAvaG9tZTEvTkVVUk8vY2FzYXp6YS9QUlNpY2VfbGludXhcCiAgICAtLWJhc2UgL2hvbWUxL05FVVJPL2Nhc2F6emEvbmFsbHNfUEQuUUMuZ3pcCiAgICAtLWJhc2UtaW5mbyBJTkZPOjAuOCBcCiAgICAtLWJhc2UtbWFmIE1BRjowLjAxIFwKICAgIC0tY292IFRFUlJFLmNvdmFyaWF0ZSBcCiAgICAtLWJpbmFyeS10YXJnZXQgVFwKICAgIC0tYmV0YSAgXAogICAgLS1sZCAvaG9tZTEvTkVVUk8vY2FzYXp6YS8xMDAwR19wbGluay9FVVJfcGhhc2UzICBcCiAgICAtLW91dCBURVJSRV9QUlNpY2UgXAogICAgLXEgNVwKICAgIC0tYWxsLXNjb3JlXAogICAgLS1waGVubyBURVJSRS5waGVubyBcCiAgICAtLXNucCBTTlAgXAogICAgLS1zdGF0IGIgXAogICAgLS1wdmFsdWUgcFwKICAgIC0tdGFyZ2V0IC9ob21lMS9ORVVSTy9jYXNhenphL2dlbm90eXBlX3FjL1RFUlJFX1FDL2FsbF9pbXB1dGVkX3IyXzMwX3JzaWRfaGFyZF9jYWxsIFwKICAgIC0tdGhyZWFkIDMyCmBgYAojIFN0ZXAgMjogRXZhbHVhdGUgb3V0cHV0CmBgYHtyLCBvdXQud2lkdGg9IjQwMHB4In0KaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfQkFSUExPVF8yMDIyLTA2LTMwLnBuZyIpCmluY2x1ZGVfZ3JhcGhpY3MoInByc2ljZV9pbWFnZXMvVEVSUkVfUFJTaWNlX0hJR0gtUkVTX1BMT1RfMjAyMi0wNi0zMC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9RVUFOVElMRVNfUExPVF8yMDIyLTA2LTMwLnBuZyIpCgppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlX0JBUlBMT1RfMjAyMi0xMC0wNC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlX0hJR0gtUkVTX1BMT1RfMjAyMi0xMC0wNC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19tYWxlX1FVQU5USUxFU19QTE9UXzIwMjItMTAtMDQucG5nIikKCmluY2x1ZGVfZ3JhcGhpY3MoInByc2ljZV9pbWFnZXMvVEVSUkVfUFJTaWNlX25hbGxzX2ZlbWFsZV9CQVJQTE9UXzIwMjItMTAtMDQucG5nIikKaW5jbHVkZV9ncmFwaGljcygicHJzaWNlX2ltYWdlcy9URVJSRV9QUlNpY2VfbmFsbHNfZmVtYWxlX0hJR0gtUkVTX1BMT1RfMjAyMi0xMC0wNC5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCJwcnNpY2VfaW1hZ2VzL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGVfUVVBTlRJTEVTX1BMT1RfMjAyMi0xMC0wNC5wbmciKQpgYGAKIyMgUGxvdHRpbmcgUFJTaWNlIERhdGEgb24gbXkgb3duCmBgYHtyfQpsaWJyYXJ5KGdnbmV3c2NhbGUpCnByc2ljZV9tYWxlX21ldGEgPC0gZnJlYWQoInByc2ljZV9uYWxsc19tYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX21hbGUucHJzaWNlIikKZ2dwbG90KHByc2ljZV9tYWxlX21ldGFbVGhyZXNob2xkIDw9IDAuNV0sIGFlcyhUaHJlc2hvbGQsIE51bV9TTlAsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKDAsIDFlNSwgMi41ZTQpLCBzZXEoMmU1LCA2ZTUsIDFlNSkpKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwcnNpY2VfZmVtYWxlX21ldGEgPC0gZnJlYWQoInByc2ljZV9uYWxsc19mZW1hbGVfZGF0YS9URVJSRV9QUlNpY2VfbmFsbHNfZmVtYWxlLnByc2ljZSIpCmdncGxvdChwcnNpY2VfZmVtYWxlX21ldGFbVGhyZXNob2xkIDw9IDAuNV0sIGFlcyhUaHJlc2hvbGQsIE51bV9TTlAsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoc2VxKDAsIDFlNSwgMi41ZTQpLCBzZXEoMmU1LCA2ZTUsIDFlNSkpKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwcnNpY2VfbWV0YSA8LSBmcmVhZCgicHJzaWNlX2RhdGEvVEVSUkVfUFJTaWNlLnByc2ljZSIpCmdncGxvdChtYXBwaW5nID0gYWVzKFRocmVzaG9sZCwgUjIsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9mZW1hbGVfbWV0YSwgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAibGlnaHRwaW5rNCIsIGhpZ2ggPSAibGlnaHRwaW5rIikgKwogIGxhYnMoY29sb3IgPSBicXVvdGUoIkZlbWFsZSBsb2ciWyIxMCJdIH4gIihQKSIpKSArCiAgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9tYWxlX21ldGEsIHNpemUgPSAxLCBhZXMoY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZTQiLCBoaWdoID0gImxpZ2h0Ymx1ZSIpICsKICBsYWJzKHkgPSBicXVvdGUoIlIiXjIpLCB4ID0gIkdXQVMgUC1WYWx1ZSBUaHJlc2hvbGQiLCBjb2xvciA9IGJxdW90ZSgiTWFsZSAtbG9nIlsiMTAiXSB+ICIoUCkiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmdncGxvdChtYXBwaW5nID0gYWVzKFRocmVzaG9sZCwgUjIsIGNvbG9yID0gLWxvZzEwKFApKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9mZW1hbGVfbWV0YSwgc2l6ZSA9IDEpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAibGlnaHRwaW5rNCIsIGhpZ2ggPSAibGlnaHRwaW5rIixndWlkZSA9IGd1aWRlX2NvbG9yYmFyKG9yZGVyPTMpKSArCiAgbGFicyhjb2xvciA9IGJxdW90ZSgiRmVtYWxlIC1sb2ciWyIxMCJdIH4gIihQKSIpKSArCiAgbmV3X3NjYWxlX2NvbG9yKCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHByc2ljZV9tYWxlX21ldGEsIHNpemUgPSAxLCBhZXMoY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZTQiLCBoaWdoID0gImxpZ2h0Ymx1ZSIsZ3VpZGUgPSBndWlkZV9jb2xvcmJhcihvcmRlcj0yKSkgKwogIGxhYnMoY29sb3IgPSBicXVvdGUoIk1hbGUgLWxvZyJbIjEwIl0gfiAiKFApIikpICsKICBuZXdfc2NhbGVfY29sb3IoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gcHJzaWNlX21ldGEsIHNpemUgPSAxLCBhZXMoY29sb3IgPSAtbG9nMTAoUCkpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImdyYXk0MCIsIGhpZ2ggPSAiZ3JheTgwIixndWlkZSA9IGd1aWRlX2NvbG9yYmFyKG9yZGVyPTEpKSArCiAgbGFicyh5ID0gYnF1b3RlKCJSIl4yKSwgeCA9ICJHV0FTIFAtVmFsdWUgVGhyZXNob2xkIiwgY29sb3IgPSBicXVvdGUoIkNyb3NzLXNleCAtbG9nIlsiMTAiXSB+ICIoUCkiKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NykpCmBgYAoKIyBTdGVwIDMgcnVuIGxpbmVhciBtb2RlbCBhdCBkaWZmZXJlbnQgdGhyZXNob2xkcyBmb3IgU05QIGluY2x1c2lvbgpUaGlzIGlzIHVwZGF0ZWQgdG8gcmVjZW50bHkgcHJvY2Vzc2VkIEROQW0gRGF0YSAyMCBvdXRsaWVycyBpbiBETkFtIHJlbW92ZWQ6CmBgYHtyfQpsb2FkKCIvaG9tZTEvTkVVUk8vU0hBUkVfREVDSVBIRVIvcHJvY2Vzc2VkX0ROQW1fZGF0YS8yMDIyL1RFUlJFX3Byb2Nlc3NlZF8yMDIyLzEtVEVSUkVfUkdfZmlsdGVyZWQuUkRhdGEiKSAjUERfUkdfZmlsdGVyZWQKIyBBc3NpZ24gZ2Vub3R5cGluZyBJRCB0byBkYXRhCm9yaWdpbmFsX2NvdmFycyA8LSBmcmVhZCgiL2hvbWUxL05FVVJPL1NIQVJFX0RFQ0lQSEVSL3RlcnJlX21ldGFfbWFzdGVyLmNzdiIpWywgLihwYXRpZW50LCBJSUQgPSBnc3ViKCJfUEFFLioiLCAiIiwgSUlEKSldCmJldGFzX2NvbWJhdCA8LSBtaW5maTo6Z2V0QmV0YShQRF9SR19maWx0ZXJlZCkKY29sbmFtZXMoYmV0YXNfY29tYmF0KSA8LSBvcmlnaW5hbF9jb3ZhcnMkSUlEW21hdGNoKGNvbG5hbWVzKGJldGFzX2NvbWJhdCksIG9yaWdpbmFsX2NvdmFycyRwYXRpZW50KV0KYmV0YXNfY29tYmF0IDwtIGJldGFzX2NvbWJhdFssIGNvbG5hbWVzKGJldGFzX2NvbWJhdCkgJWluJSBjb3ZhcmlhdGUkSUlEXQpgYGAKTGV0J3MgY2hlY2sgaG93IHRoZSBkYXRhIGxvb2tzIGZvciB0aGUgZmlyc3QgNSBzdWJqZWN0czoKYGBge3J9CmdncGxvdChiZXRhc19jb21iYXRbLCAxOjVdICU+JSBhcy5kYXRhLnRhYmxlKGtlZXAucm93bmFtZXMgPSBUKSAlPiUgbWVsdChpZC52YXJzID0gInJuIiwgdmFsdWUubmFtZSA9ICJiZXRhcyIsIHZhcmlhYmxlLm5hbWUgPSAic3ViamVjdCIpLCBhZXMoYmV0YXMsIGNvbG9yID0gc3ViamVjdCkpKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKIyMjIE1hdGNoIEROQSwgUFJTLCBhbmQgbWV0YWRhdGEgQFRPRE8gZml4IHRoaXMgYWZ0ZXIgdXBkYXRlIG9mIFBSUyBldGMuCmBgYHtyfQpwcnNpY2VfYmVzdCA8LSBmcmVhZCgicHJzaWNlX2RhdGEvVEVSUkVfUFJTaWNlLmJlc3QiKVttYXRjaChjb2xuYW1lcyhiZXRhc19jb21iYXQpLCBJSUQsbm9tYXRjaD0wKSwuKGJlc3Q9UFJTKV0KcHJzaWNlX2FsbCA8LSBjYmluZCgKICBmcmVhZCgicHJzaWNlX2RhdGEvVEVSUkVfUFJTaWNlLmFsbF9zY29yZSIpW21hdGNoKGNvbG5hbWVzKGJldGFzX2NvbWJhdCksIElJRCxub21hdGNoPTApLCAuKEZJRCwgSUlELCBgUHRfNWUtMDhgLCBgUHRfNS4wMDVlLTA1YCwgYFB0XzAuMDAwMTAwMDVgLCBgUHRfMC4wMDEwMDAwNWAsIGBQdF8wLjAxMDE1MDFgLCBgUHRfMC4xYCwgYFB0XzAuMmAsIGBQdF8wLjNgLCBgUHRfMC40YCwgYFB0XzAuNWAsIGBQdF8xYCldLAogIHByc2ljZV9iZXN0CikKY292YXJpYXRlIDwtIGNvdmFyaWF0ZVttYXRjaChjb2xuYW1lcyhiZXRhc19jb21iYXQpLCBJSUQpXQphbGwoY292YXJpYXRlJElJRCA9PSBjb2xuYW1lcyhiZXRhc19jb21iYXQpKQphbGwoY292YXJpYXRlJElJRCA9PSBwcnNpY2VfYWxsJElJRCkKCmNvdmFyaWF0ZV9tYWxlIDwtIGNvdmFyaWF0ZVtzZXggPT0gMV0gJT4lIHNlbGVjdCgtc2V4KQpiZXRhc19tYWxlIDwtIGJldGFzX2NvbWJhdFssIGNvdmFyaWF0ZV9tYWxlJElJRF0KcHJzaWNlX21hbGVfYmVzdCA8LSBmcmVhZCgicHJzaWNlX25hbGxzX21hbGVfZGF0YS9URVJSRV9QUlNpY2VfbmFsbHNfbWFsZS5iZXN0IilbbWF0Y2goY29sbmFtZXMoYmV0YXNfbWFsZSksIElJRCxub21hdGNoPTApLC4oYmVzdD1QUlMpXQpwcnNpY2VfbWFsZV9hbGwgPC0gY2JpbmQoCiAgZnJlYWQoInByc2ljZV9uYWxsc19tYWxlX2RhdGEvVEVSUkVfUFJTaWNlX25hbGxzX21hbGUuYWxsX3Njb3JlIilbbWF0Y2goY29sbmFtZXMoYmV0YXNfbWFsZSksIElJRCxub21hdGNoPTApLCAuKEZJRCwgSUlELCBgUHRfNWUtMDhgLCBgUHRfNS4wMDVlLTA1YCwgYFB0XzAuMDAwMTAwMDVgLCBgUHRfMC4wMDEwMDAwNWAsIGBQdF8wLjAxMDE1MDFgLCBgUHRfMC4xYCwgYFB0XzAuMmAsIGBQdF8wLjNgLCBgUHRfMC40YCwgYFB0XzAuNWAsIGBQdF8xYCldLAogIHByc2ljZV9tYWxlX2Jlc3QKKQpjb3ZhcmlhdGVfbWFsZSA8LSBjb3ZhcmlhdGVfbWFsZVttYXRjaChjb2xuYW1lcyhiZXRhc19tYWxlKSwgSUlELG5vbWF0Y2g9MCldCmFsbChjb3ZhcmlhdGVfbWFsZSRJSUQgPT0gY29sbmFtZXMoYmV0YXNfbWFsZSkpCmFsbChjb3ZhcmlhdGVfbWFsZSRJSUQgPT0gcHJzaWNlX21hbGVfYWxsJElJRCkKCnByc2ljZV9mZW1hbGVfYmVzdCA8LSBmcmVhZCgicHJzaWNlX25hbGxzX2ZlbWFsZV9kYXRhL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGUuYmVzdCIpCmNvdmFyaWF0ZV9mZW1hbGUgPC0gY292YXJpYXRlW3NleCA9PSAwXSAlPiUgc2VsZWN0KC1zZXgpICU+JSBmaWx0ZXIoSUlEICVpbiUgcHJzaWNlX2ZlbWFsZV9iZXN0JElJRCkKYmV0YXNfZmVtYWxlIDwtIGJldGFzX2NvbWJhdFssIGNvdmFyaWF0ZV9mZW1hbGUkSUlEXQpwcnNpY2VfZmVtYWxlX2Jlc3QgPC0gcHJzaWNlX2ZlbWFsZV9iZXN0W21hdGNoKGNvbG5hbWVzKGJldGFzX2ZlbWFsZSksIElJRCxub21hdGNoPTApLC4oYmVzdD1QUlMpXQpwcnNpY2VfZmVtYWxlX2FsbCA8LSBjYmluZCgKICBmcmVhZCgicHJzaWNlX25hbGxzX2ZlbWFsZV9kYXRhL1RFUlJFX1BSU2ljZV9uYWxsc19mZW1hbGUuYWxsX3Njb3JlIilbbWF0Y2goY29sbmFtZXMoYmV0YXNfZmVtYWxlKSwgSUlELG5vbWF0Y2g9MCksIC4oRklELCBJSUQsIGBQdF81ZS0wOGAsIGBQdF81LjAwNWUtMDVgLCBgUHRfMC4wMDAxMDAwNWAsIGBQdF8wLjAwMTAwMDA1YCwgYFB0XzAuMDEwMTUwMWAsIGBQdF8wLjFgLCBgUHRfMC4yYCwgYFB0XzAuM2AsIGBQdF8wLjRgLCBgUHRfMC41YCwgYFB0XzFgKV0sCiAgcHJzaWNlX2ZlbWFsZV9iZXN0CikKY292YXJpYXRlX2ZlbWFsZSA8LSBjb3ZhcmlhdGVfZmVtYWxlW21hdGNoKGNvbG5hbWVzKGJldGFzX2ZlbWFsZSksIElJRCxub21hdGNoPTApXQphbGwoY292YXJpYXRlX2ZlbWFsZSRJSUQgPT0gY29sbmFtZXMoYmV0YXNfZmVtYWxlKSkKYWxsKGNvdmFyaWF0ZV9mZW1hbGUkSUlEID09IHByc2ljZV9mZW1hbGVfYWxsJElJRCkKCgpgYGAKIyMjIFJ1biBsaW1tYQoKYGBge3J9Cm12YWx1ZXMgPC0gbHVtaTo6YmV0YTJtKGJldGFzX2NvbWJhdCkKcHJzX21hdCA8LSBwcnNpY2VfYWxsWywgLWMoMSwgMildCmNvdl9tYXQgPC0gY292YXJpYXRlWywgLWMoMSwgMildCgptdmFsdWVzX21hbGUgPC0gbHVtaTo6YmV0YTJtKGJldGFzX21hbGUpCnByc19tYXRfbWFsZSA8LSBwcnNpY2VfbWFsZV9hbGxbLCAtYygxLCAyKV0KY292X21hdF9tYWxlIDwtIGNvdmFyaWF0ZV9tYWxlWywgLWMoMSwgMildCgptdmFsdWVzX2ZlbWFsZSA8LSBsdW1pOjpiZXRhMm0oYmV0YXNfZmVtYWxlKQpwcnNfbWF0X2ZlbWFsZSA8LSBwcnNpY2VfZmVtYWxlX2FsbFssIC1jKDEsIDIpXQpjb3ZfbWF0X2ZlbWFsZSA8LSBjb3ZhcmlhdGVfZmVtYWxlWywgLWMoMSwgMildCmBgYAoKYGBge3J9CnJlZ2lzdGVyRG9QYXJhbGxlbChuY29sKHByc19tYXQpIC8gNCkKaGl0cyA8LSBmb3JlYWNoKHByc190aHJlc2ggPSBjb2xuYW1lcyhwcnNfbWF0KSkgJWRvcGFyJSB7CiAgZGVzaWduX3BycyA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0WywgLi5wcnNfdGhyZXNoXSwgY292X21hdCkpCiAgcHJzX2ZpdCA8LSBsbUZpdChtdmFsdWVzLCBkZXNpZ25fcHJzKQogIHByc19maXQgPC0gZUJheWVzKHByc19maXQpCiAgdG9wVGFibGUocHJzX2ZpdCwgY29lZiA9IDIsIGFkanVzdC5tZXRob2QgPSAiYm9uZiIsIHAudmFsdWUgPSAwLjA1LCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlcykpCn0KbmFtZXMoaGl0cykgPC0gY29sbmFtZXMocHJzX21hdCkKaGl0c19ieV90aHJlc2hfYm9uZiA8LSByYmluZGxpc3QoaGl0cywgaWRjb2wgPSAidGhyZXNob2xkIiwgZmlsbCA9IFRSVUUpCgpyZWdpc3RlckRvUGFyYWxsZWwobmNvbChwcnNfbWF0X21hbGUpIC8gNCkKaGl0c19tYWxlIDwtIGZvcmVhY2gocHJzX3RocmVzaCA9IGNvbG5hbWVzKHByc19tYXRfbWFsZSkpICVkb3BhciUgewogIGRlc2lnbl9wcnNfbWFsZSA8LSBtb2RlbC5tYXRyaXgofi4sIGRhdGEgPSBjYmluZChwcnNfbWF0X21hbGVbLCAuLnByc190aHJlc2hdLCBjb3ZfbWF0X21hbGUpKQogIHByc19maXRfbWFsZSA8LSBsbUZpdChtdmFsdWVzX21hbGUsIGRlc2lnbl9wcnNfbWFsZSkKICBwcnNfZml0X21hbGUgPC0gZUJheWVzKHByc19maXRfbWFsZSkKICB0b3BUYWJsZShwcnNfZml0X21hbGUsIGNvZWYgPSAyLCBhZGp1c3QubWV0aG9kID0gImJvbmYiLCBwLnZhbHVlID0gMC4wNSwgbnVtYmVyID0gSW5mLCBnZW5lbGlzdCA9IHJvd25hbWVzKG12YWx1ZXNfbWFsZSkpCn0KbmFtZXMoaGl0c19tYWxlKSA8LSBjb2xuYW1lcyhwcnNfbWF0X21hbGUpCmhpdHNfYnlfdGhyZXNoX2JvbmZfbWFsZSA8LSByYmluZGxpc3QoaGl0c19tYWxlLCBpZGNvbCA9ICJ0aHJlc2hvbGQiLCBmaWxsID0gVFJVRSkKCnJlZ2lzdGVyRG9QYXJhbGxlbChuY29sKHByc19tYXRfZmVtYWxlKSAvIDQpCmhpdHNfZmVtYWxlIDwtIGZvcmVhY2gocHJzX3RocmVzaCA9IGNvbG5hbWVzKHByc19tYXRfZmVtYWxlKSkgJWRvcGFyJSB7CiAgZGVzaWduX3Byc19mZW1hbGUgPC0gbW9kZWwubWF0cml4KH4uLCBkYXRhID0gY2JpbmQocHJzX21hdF9mZW1hbGVbLCAuLnByc190aHJlc2hdLCBjb3ZfbWF0X2ZlbWFsZSkpCiAgcHJzX2ZpdF9mZW1hbGUgPC0gbG1GaXQobXZhbHVlc19mZW1hbGUsIGRlc2lnbl9wcnNfZmVtYWxlKQogIHByc19maXRfZmVtYWxlIDwtIGVCYXllcyhwcnNfZml0X2ZlbWFsZSkKICB0b3BUYWJsZShwcnNfZml0X2ZlbWFsZSwgY29lZiA9IDIsIGFkanVzdC5tZXRob2QgPSAiYm9uZiIsIHAudmFsdWUgPSAwLjA1LCBudW1iZXIgPSBJbmYsIGdlbmVsaXN0ID0gcm93bmFtZXMobXZhbHVlc19mZW1hbGUpKQp9Cm5hbWVzKGhpdHNfZmVtYWxlKSA8LSBjb2xuYW1lcyhwcnNfbWF0X2ZlbWFsZSkKaGl0c19ieV90aHJlc2hfYm9uZl9mZW1hbGUgPC0gcmJpbmRsaXN0KGhpdHNfZmVtYWxlLCBpZGNvbCA9ICJ0aHJlc2hvbGQiLCBmaWxsID0gVFJVRSkKCmBgYAoKIyMjIFBsb3R0aW5nIEVXQVMgdnMgVGhyZXNob2xkIEV4cGVyaW1lbnQgYnkgU2V4CmBgYHtyfQp0b19wbG90IDwtIHJiaW5kKAogIGhpdHNfYnlfdGhyZXNoX2JvbmZbLCAuKGhpdHMgPSAuTiwgU2V4ID0gIkNyb3NzLXNleCIpLCBieSA9IHRocmVzaG9sZF0gJT4lCiAgICBtdXRhdGUodGhyZXNob2xkID0gcmVjb2RlX2ZhY3Rvcih0aHJlc2hvbGQsIGBQdF8wLjAyMTkwMDFgID0gIjAuMDIxOSIsIGBQdF81ZS0wOGAgPSAiNWUtOCIsIGBQdF81LjAwNWUtMDVgID0gIjVlLTUiLCBgUHRfMC4wMDAxMDAwNWAgPSAiMWUtNCIsIGBQdF8wLjAwMTAwMDA1YCA9ICIxZS0zIiwgYFB0XzAuMDEwMTUwMWAgPSAiMWUtMiIsIGBQdF8wLjFgID0gIjAuMSIsIGBQdF8wLjJgID0gIjAuMiIsIGBQdF8wLjNgID0gIjAuMyIsIGBQdF8wLjRgID0gIjAuNCIsIGBQdF8wLjVgID0gIjAuNSIsIGBQdF8xYCA9ICIxLjAiKSksCiAgaGl0c19ieV90aHJlc2hfYm9uZl9tYWxlWywgLihoaXRzID0gLk4sIFNleCA9ICJNYWxlIiksIGJ5ID0gdGhyZXNob2xkXSAlPiUKICAgIG11dGF0ZSh0aHJlc2hvbGQgPSByZWNvZGVfZmFjdG9yKHRocmVzaG9sZCwgYFB0XzAuMDIxOTAwMWAgPSAiMC4wMjE5IiwgYFB0XzVlLTA4YCA9ICI1ZS04IiwgYFB0XzUuMDA1ZS0wNWAgPSAiNWUtNSIsIGBQdF8wLjAwMDEwMDA1YCA9ICIxZS00IiwgYFB0XzAuMDAxMDAwMDVgID0gIjFlLTMiLCBgUHRfMC4wMTAxNTAxYCA9ICIxZS0yIiwgYFB0XzAuMWAgPSAiMC4xIiwgYFB0XzAuMmAgPSAiMC4yIiwgYFB0XzAuM2AgPSAiMC4zIiwgYFB0XzAuNGAgPSAiMC40IiwgYFB0XzAuNWAgPSAiMC41IiwgYFB0XzFgID0gIjEuMCIpKSwKICBoaXRzX2J5X3RocmVzaF9ib25mX2ZlbWFsZVssIC4oaGl0cyA9IC5OLCBTZXggPSAiRmVtYWxlIiksIGJ5ID0gdGhyZXNob2xkXSAlPiUKICAgIG11dGF0ZSh0aHJlc2hvbGQgPSByZWNvZGVfZmFjdG9yKHRocmVzaG9sZCwgYFB0XzAuMDIxOTAwMWAgPSAiMC4wMjE5IiwgYFB0XzVlLTA4YCA9ICI1ZS04IiwgYFB0XzUuMDA1ZS0wNWAgPSAiNWUtNSIsIGBQdF8wLjAwMDEwMDA1YCA9ICIxZS00IiwgYFB0XzAuMDAxMDAwMDVgID0gIjFlLTMiLCBgUHRfMC4wMTAxNTAxYCA9ICIxZS0yIiwgYFB0XzAuMWAgPSAiMC4xIiwgYFB0XzAuMmAgPSAiMC4yIiwgYFB0XzAuM2AgPSAiMC4zIiwgYFB0XzAuNGAgPSAiMC40IiwgYFB0XzAuNWAgPSAiMC41IiwgYFB0XzFgID0gIjEuMCIpKQopICU+JSBtdXRhdGUoU2V4ID0gZmFjdG9yKFNleCwgbGV2ZWxzID0gYygiQ3Jvc3Mtc2V4IiwgIk1hbGUiLCAiRmVtYWxlIikpKQpwbG90X3BvcyA8LSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpCmdncGxvdCh0b19wbG90LCBhZXModGhyZXNob2xkLCBoaXRzLCBmaWxsID0gU2V4LCBsYWJlbCA9IGhpdHMpKSArCiAgZ2VvbV90ZXh0KHBvc2l0aW9uID0gcGxvdF9wb3MsIHZqdXN0ID0gLTAuMjUpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBsb3RfcG9zKSArCiAgbGFicyh4ID0gIkdXQVMgUCBWYWx1ZSBUaHJlc2hvbGQiLCB5ID0gIkVXQVMgSGl0cyIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5ODAiLCAibGlnaHRibHVlIiwgImxpZ2h0cGluayIpKSArCiAgdGhlbWVfbWluaW1hbCgpCmhpdHNfYnlfdGhyZXNoX2JvbmZbLCAuKGhpdHMgPSAuTiwgU2V4ID0gIkNyb3NzLXNleCIpLCBieSA9IHRocmVzaG9sZF0KaGl0c19ieV90aHJlc2hfYm9uZl9tYWxlWywgLihoaXRzID0gLk4pLCBieSA9IHRocmVzaG9sZF0KaGl0c19ieV90aHJlc2hfYm9uZl9mZW1hbGVbLCAuKGhpdHMgPSAuTiksIGJ5ID0gdGhyZXNob2xkXQpgYGAKYGBge3J9CmRpc3BsYXlfdmVubiA8LSBmdW5jdGlvbih4LCAuLi4pIHsKICBsaWJyYXJ5KFZlbm5EaWFncmFtKQogIGdyaWQubmV3cGFnZSgpCiAgdmVubl9vYmplY3QgPC0gdmVubi5kaWFncmFtKHgsIGZpbGVuYW1lID0gTlVMTCwgLi4uKQogIGdyaWQuZHJhdyh2ZW5uX29iamVjdCkKfQoKZGlzcGxheV92ZW5uKGxpc3QoYENyb3NzLXNleGAgPSBoaXRzX2J5X3RocmVzaF9ib25mW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRCwgTWFsZSA9IGhpdHNfYnlfdGhyZXNoX2JvbmZfbWFsZVt0aHJlc2hvbGQgPT0gIlB0XzVlLTA4Il0kSUQsIEZlbWFsZSA9IGhpdHNfYnlfdGhyZXNoX2JvbmZfZmVtYWxlW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRCksIGZpbGwgPSBjKCJncmF5ODAiLCAibGlnaHRibHVlIiwgImxpZ2h0cGluayIpKQptYWxlX2lkcyA8LSBoaXRzX2J5X3RocmVzaF9ib25mX21hbGVbdGhyZXNob2xkID09ICJQdF81ZS0wOCJdJElECmNyb3NzX2lkcyA8LSBoaXRzX2J5X3RocmVzaF9ib25mW3RocmVzaG9sZCA9PSAiUHRfNWUtMDgiXSRJRAptYWxlX2lkc1shbWFsZV9pZHMgJWluJSBjcm9zc19pZHNdCmBgYAoKYGBge3J9CmdldF9mdWxsX2ZpdCA8LSBmdW5jdGlvbihwcnNfbWF0LGNvdl9tYXQsbXZhbHVlcyl7CiAgdG9wX2Rlc2lnbl9wcnMgPC0gbW9kZWwubWF0cml4KH4uLCBkYXRhID0gY2JpbmQocHJzX21hdFssIGBQdF81ZS0wOGBdLCBjb3ZfbWF0KSkKICB0b3BfcHJzX2ZpdCA8LSBsbUZpdChtdmFsdWVzLCB0b3BfZGVzaWduX3BycykKICB0b3BfcHJzX2ZpdCA8LSBlQmF5ZXModG9wX3Byc19maXQpCiAgdG9wX3Byc19oaXRzIDwtIHRvcFRhYmxlKHRvcF9wcnNfZml0LCBjb2VmID0gMiwgYWRqdXN0Lm1ldGhvZCA9ICJib25mIiwgbnVtYmVyID0gSW5mLCBnZW5lbGlzdCA9IHJvd25hbWVzKG12YWx1ZXMpKQp9CnRvcF9wcnNfaGl0cyA8LSBnZXRfZnVsbF9maXQocHJzX21hdCxjb3ZfbWF0LG12YWx1ZXMpCnRvcF9tYWxlX3Byc19oaXRzIDwtIGdldF9mdWxsX2ZpdChwcnNfbWF0X21hbGUsIGNvdl9tYXRfbWFsZSwgbXZhbHVlc19tYWxlKQp0b3BfZmVtYWxlX3Byc19oaXRzIDwtIGdldF9mdWxsX2ZpdChwcnNfbWF0X2ZlbWFsZSwgY292X21hdF9mZW1hbGUsIG12YWx1ZXNfZmVtYWxlKQpzYXZlKGxpc3Q9YygidG9wX3Byc19oaXRzIiwidG9wX21hbGVfcHJzX2hpdHMiLCJ0b3BfZmVtYWxlX3Byc19oaXRzIiksZmlsZT0icHJzX25hbGxzX2Nyb3NzX3dfc2V4X3N0cmF0aWZpZWQuUkRhdGEiKQpgYGAKCmBgYHtyfQpsb2FkKCJwcnNfbmFsbHNfY3Jvc3Nfd19zZXhfc3RyYXRpZmllZC5SRGF0YSIpCmBgYApgYGB7cn0KbWFuaWZlc3QgPC0gSWxsdW1pbmFIdW1hbk1ldGh5bGF0aW9uRVBJQ2Fubm8uaWxtMTBiNC5oZzE5OjpPdGhlciAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJuYW1lIikKcHJzX2Fubm90IDwtIGRhdGEudGFibGUodG9wX3Byc19oaXRzKVttYW5pZmVzdCwgZ2VuZSA6PSBnc3ViKCI7LioiLCAiIiwgVUNTQ19SZWZHZW5lX05hbWUpLCBvbiA9IGMoSUQgPSAibmFtZSIpXQpwcnNfYW5ub3RfbWFsZSA8LSBkYXRhLnRhYmxlKHRvcF9tYWxlX3Byc19oaXRzKVttYW5pZmVzdCwgZ2VuZSA6PSBnc3ViKCI7LioiLCAiIiwgVUNTQ19SZWZHZW5lX05hbWUpLCBvbiA9IGMoSUQgPSAibmFtZSIpXQpwcnNfYW5ub3RfZmVtYWxlPC0gZGF0YS50YWJsZSh0b3BfZmVtYWxlX3Byc19oaXRzKVttYW5pZmVzdCwgZ2VuZSA6PSBnc3ViKCI7LioiLCAiIiwgVUNTQ19SZWZHZW5lX05hbWUpLCBvbiA9IGMoSUQgPSAibmFtZSIpXQpwbG90X3Byc19oaXRzIDwtIGZ1bmN0aW9uKHByc19hbm5vdCxsYWJlbF9jb2xvcil7CiAgZ2dwbG90KHByc19hbm5vdCwgYWVzKGxvZ0ZDLCAtbG9nMTAoUC5WYWx1ZSkpKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9wb2ludCgKICAgICAgZGF0YSA9IHN1YnNldChwcnNfYW5ub3QsIGFkai5QLlZhbCA8IDAuMDUgJiBhYnMobG9nRkMpID4gMC4wMyksCiAgICAgIGNvbG9yID0gbGFiZWxfY29sb3IsCiAgICAgIG1hcHBpbmcgPSBhZXMobG9nRkMsIC1sb2cxMChQLlZhbHVlKSkKICAgICkgKwogICAgZ2VvbV9obGluZSgKICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwKICAgICAgeWludGVyY2VwdCA9IG1pbigtbG9nMTAocHJzX2Fubm90JFAuVmFsdWVbcHJzX2Fubm90JGFkai5QLlZhbCA8IDAuMDVdKSkKICAgICkgKwogICAgZ2VvbV92bGluZShsaW5ldHlwZSA9ICJkYXNoZWQiLCB4aW50ZXJjZXB0ID0gMC4wMykgKwogICAgZ2VvbV92bGluZShsaW5ldHlwZSA9ICJkYXNoZWQiLCB4aW50ZXJjZXB0ID0gLTAuMDMpICsKICAgIGdlb21fdGV4dF9yZXBlbCgKICAgICAgZGF0YSA9IHByc19hbm5vdCAlPiUgZmlsdGVyKGFicyhsb2dGQykgPiAwLjAzICYgYWRqLlAuVmFsIDwgMC4wNSksCiAgICAgIGNvbG9yID0gImRvZGdlcmJsdWUiLAogICAgICBtYXBwaW5nID0gYWVzKGxvZ0ZDLCAtbG9nMTAoUC5WYWx1ZSksIGxhYmVsID0gaWZlbHNlKGdlbmUgIT0gIiIsIGdlbmUsIElEKSksCiAgICAgIHNpemUgPSAzLAogICAgICBtYXgub3ZlcmxhcHMgPSAyMAogICAgKSArCiAgICBsYWJzKHkgPSBicXVvdGUoImxvZyJbMTBdIH4gIihQKSIpLCB4ID0gcXVvdGUoRGVsdGEgfiAiTSIgfiBNZXRoeWxhdGlvbikpICsKICAgIHRoZW1lX21pbmltYWwoKQp9CgpwbG90X3Byc19oaXRzKHByc19hbm5vdCwiZ3JheTQwIikKcGxvdF9wcnNfaGl0cyhwcnNfYW5ub3RfbWFsZSwibGlnaHRibHVlIikKcGxvdF9wcnNfaGl0cyhwcnNfYW5ub3RfZmVtYWxlLCJwaW5rIikKYGBgCgoKYGBge3J9CnByc19wbG90X2RhdGEgPC0gZGF0YS50YWJsZShkbmFtID0gbHVtaTo6bTJiZXRhKG12YWx1ZXNbImNnMTI2MDk3ODUiLF0pLCBwcnMgPSBwcnNfbWF0JGBQdF81ZS0wOGAsUEQ9aWZlbHNlKFBEW21hdGNoKGNvbG5hbWVzKG12YWx1ZXMpLElJRCksXSRQRCA9PSAxLCJDYXNlIiwiQ29udHJvbCIpLFNleD1mYWN0b3IoaWZlbHNlKGNvdl9tYXQkc2V4ID09MSwiTWFsZSIsIkZlbWFsZSIpLGxldmVscz1jKCJNYWxlIiwiRmVtYWxlIikpKQpnZ3Bsb3QocHJzX3Bsb3RfZGF0YSxhZXMocHJzLGRuYW0sY29sb3I9U2V4LHNoYXBlID0gUEQsZ3JvdXA9U2V4KSkgKwogIGdlb21fcG9pbnQoc2l6ZT0zKSsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIixzZT1GKSsKICBsYWJzKHk9YnF1b3RlKCJNZXRoeWxhdGlvbiJ+YmV0YSkseD0iUGFya2luc29uJ3MgR1JTIikrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJNYWxlIj0ibGlnaHRibHVlIiwiRmVtYWxlIj0ibGlnaHRwaW5rIikpICsgCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemU9MjApCmBgYAoKIyMgZ28gZW5yaWNobWVudD8KYGBge3IsZXZhbD1GQUxTRX0KbGlicmFyeShncHJvZmlsZXIyKQpjcm9zc19zZXggPC0gdW5pcXVlKGdzdWIoIjsuKiIsIiIsbWFuaWZlc3RbbWFuaWZlc3QkbmFtZSAlaW4lIGhpdHNfYnlfdGhyZXNoX2JvbmZbdGhyZXNob2xkID09ICJQdF81ZS0wOCJdJElELF0kVUNTQ19SZWZHZW5lX05hbWUpKQpiYWNrZ3JvdW5kIDwtIHVuaXF1ZShnc3ViKCI7LioiLCIiLG1hbmlmZXN0JFVDU0NfUmVmR2VuZV9OYW1lKSkKZ29zdF9yZXMgPC0gZ29zdChxdWVyeT1jcm9zc19zZXgsY3VzdG9tX2JnID0gYmFja2dyb3VuZCkKZ29zdHBsb3QoZ29zdF9yZXMpCmBgYApgYGB7cn0KY3BnX3BvcyA8LSBJbGx1bWluYUh1bWFuTWV0aHlsYXRpb25FUElDYW5uby5pbG0xMGI0LmhnMTk6OkxvY2F0aW9ucyAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJuYW1lIikKbWFsZV9hbm5vdF9jcGcgPC0gKHByc19hbm5vdF9tYWxlICU+JSBmaWx0ZXIoYWRqLlAuVmFsIDwgMC4yNSkgJT4lIGxlZnRfam9pbihjcGdfcG9zLGJ5PWMoIklEIj0ibmFtZSIpKSAlPiUgZ3JvdXBfYnkoY2hyKSAlPiUgdG9wX24oLTEwLFAuVmFsdWUpKSRJRApmZW1hbGVfYW5ub3RfY3BnIDwtIChwcnNfYW5ub3RfZmVtYWxlICU+JSBmaWx0ZXIoYWRqLlAuVmFsIDwgMC4yNSkgJT4lIGxlZnRfam9pbihjcGdfcG9zLGJ5PWMoIklEIj0ibmFtZSIpKSAlPiUgZ3JvdXBfYnkoY2hyKSAlPiUgdG9wX24oLTEwLFAuVmFsdWUpKSRJRApsaWJyYXJ5KGh1ZHNvbikKb3B0aW9ucyhnZ3JlcGVsLm1heC5vdmVybGFwcyA9IEluZikKZ21pcnJvcigKICBwcnNfYW5ub3RfbWFsZVssLihTTlA9SUQsQ0hSPWdzdWIoImNociIsIiIsY3BnX3Bvc1ttYXRjaChJRCxjcGdfcG9zJG5hbWUpLF0kY2hyKSxQT1M9Y3BnX3Bvc1ttYXRjaChJRCxjcGdfcG9zJG5hbWUpLF0kcG9zLHB2YWx1ZT1QLlZhbHVlKV0sCiAgcHJzX2Fubm90X2ZlbWFsZVssLihTTlA9SUQsQ0hSPWdzdWIoImNociIsIiIsY3BnX3Bvc1ttYXRjaChJRCxjcGdfcG9zJG5hbWUpLF0kY2hyKSxQT1M9Y3BnX3Bvc1ttYXRjaChJRCxjcGdfcG9zJG5hbWUpLF0kcG9zLHB2YWx1ZT1QLlZhbHVlKV0sCiAgYW5ub3RhdGVfc25wID0gYyhtYWxlX2Fubm90X2NwZyxmZW1hbGVfYW5ub3RfY3BnKSwKICB0bGluZSA9ICBtYXgocHJzX2Fubm90X21hbGVbYWRqLlAuVmFsPDAuMjVdJFAuVmFsdWUpLAogIGJsaW5lID0gIG1heChwcnNfYW5ub3RfZmVtYWxlW2Fkai5QLlZhbDwwLjI1XSRQLlZhbHVlKSwKICBoaWdobGlnaHRfcCA9IGMobWF4KHByc19hbm5vdF9tYWxlW2Fkai5QLlZhbDwwLjI1XSRQLlZhbHVlKSxtYXgocHJzX2Fubm90X2ZlbWFsZVthZGouUC5WYWw8MC4yNV0kUC5WYWx1ZSkpLAogIHRvcHRpdGxlPSJNYWxlIiwKICBib3R0b210aXRsZSA9IkZlbWFsZSIsCiAgaGlnaGxpZ2h0ZXI9ImdyZWVuIiwKICBiYWNrZ3JvdW5kPSJ3aGl0ZSIKKQoKYGBgCgojIE1hbmhhdHRhbiBwbG90IHZzIEdXQVMgbWFuaGF0dGFuIHBsb3QKYGBge3IsZXZhbD1GQUxTRX0KbGlicmFyeShxcW1hbikKCmNvcHlfYW5ub3QgPC0gcHJzX2Fubm90W2NwZ19wb3MsIG9uID0gYyhJRCA9ICJuYW1lIildICU+JQogIG11dGF0ZShjaHIgPSBhcy5udW1lcmljKHJlY29kZShnc3ViKCJjaHIiLCAiIiwgY2hyKSxYPSIyMyIsWT0iMjQiKSkpCnRvX3Bsb3QgPC0gY29weV9hbm5vdFssIC4oU05QID0gZ2VuZSwgQ0hSID0gY2hyLCBCUCA9IHBvcywgUCA9IFAuVmFsdWUsIEZEUiA9IGFkai5QLlZhbCldWyFpcy5uYShQKV0KbWFuaGF0dGFuKHRvX3Bsb3QsCiAgYW5ub3RhdGVQdmFsID0gbWF4KHRvX3Bsb3RbRkRSIDwgMC4wNV0kUCksCiAgYW5ub3RhdGVUb3AgPSBUUlVFLAogIGdlbm9tZXdpZGVsaW5lID0gbWluKC1sb2cxMCh0b19wbG90W0ZEUiA8IDAuMDVdJFApKSwKICBzdWdnZXN0aXZlbGluZSA9IEZBTFNFCikKbWFuaGF0dGFuKHRvX3Bsb3RbQ0hSID09IDE3XSwKICBhbm5vdGF0ZVB2YWwgPSBtYXgodG9fcGxvdFtGRFIgPCAwLjA1XSRQKSwKICBhbm5vdGF0ZVRvcCA9IEZBTFNFLAogIGdlbm9tZXdpZGVsaW5lID0gbWluKC1sb2cxMCh0b19wbG90W0ZEUiA8IDAuMDVdJFApKSwKICBzdWdnZXN0aXZlbGluZSA9IEZBTFNFCikKcXEodG9fcGxvdCRQKQpgYGAKCgojIyBETVJzCgpgYGB7cn0KbGlicmFyeShETVJjYXRlKQpTNF90b19kYXRhZnJhbWUgPC0gZnVuY3Rpb24oczRvYmopIHsKICBubXMgPC0gc2xvdE5hbWVzKHM0b2JqKQogIGxzdCA8LSBsYXBwbHkobm1zLCBmdW5jdGlvbihubSkgc2xvdChzNG9iaiwgbm0pKQogIGFzLmRhdGEuZnJhbWUoc2V0TmFtZXMobHN0LCBubXMpKQp9CnJ1bl9kbXJjYXRlIDwtIGZ1bmN0aW9uKHByc19tYXQsY292X21hdCxtdmFsdWVzKXsKICBkZXNpZ25fcHJzIDwtIG1vZGVsLm1hdHJpeCh+LiwgZGF0YSA9IGNiaW5kKHByc19tYXRbLCBgUHRfNWUtMDhgXSwgY292X21hdCkpCiAgcHJzX2Fubm90YXRlZCA8LSBjcGcuYW5ub3RhdGUoZGF0YXR5cGUgPSAiYXJyYXkiLCBvYmplY3QgPSBtdmFsdWVzLCBhbmFseXNpcy50eXBlID0gImRpZmZlcmVudGlhbCIsIGRlc2lnbiA9IGRlc2lnbl9wcnMsIGNvZWYgPSAyLCB3aGF0ID0gIk0iLCBhcnJheXR5cGUgPSAiRVBJQyIsIGZkciA9IDAuMDUpCiAgcHJzX2Rtcl9yZXMgPC0gZG1yY2F0ZShwcnNfYW5ub3RhdGVkLCBsYW1iZGEgPSAxMDAwLCBDID0gMikKICByZXR1cm4oUzRfdG9fZGF0YWZyYW1lKHByc19kbXJfcmVzKSkKfQpkbXJfY3Jvc3MgPC0gcnVuX2RtcmNhdGUocHJzX21hdCwgY292X21hdCwgbXZhbHVlcykKZG1yX21hbGVzIDwtIHJ1bl9kbXJjYXRlKHByc19tYXRfbWFsZSxjb3ZfbWF0X21hbGUsbXZhbHVlc19tYWxlKQpkbXJfZmVtYWxlIDwtIHJ1bl9kbXJjYXRlKHByc19tYXRfZmVtYWxlLGNvdl9tYXRfZmVtYWxlLG12YWx1ZXNfZmVtYWxlKQpgYGAKYGBge3J9CmFubm90YXRpb24gPC0gbWluZmk6OmdldEFubm90YXRpb24oSWxsdW1pbmFIdW1hbk1ldGh5bGF0aW9uRVBJQ2Fubm8uaWxtMTBiNC5oZzE5KQpgYGAKIyMjIFBsb3R0aW5nIGFsbCBETVJzIHsudGFic2V0IC50YWJzZXQtZmFkZX0KYGBge3J9CmdldF9kbXJfZWZmZWN0cyA8LSBmdW5jdGlvbihkbXIsIGxpbW1hX3JlcyxtdmFsdWVzKSB7CiAgZG1yX2Nvb3JkIDwtIHN0cl9tYXRjaF9hbGwoYXMuY2hhcmFjdGVyKGRtciksICIoY2hyLiopOihbMC05XSopLShbMC05XSopIilbWzFdXQogIGNwZ3MgPC0gYXMuZGF0YS50YWJsZShhbm5vdGF0aW9uW2Fubm90YXRpb24kY2hyID09IGRtcl9jb29yZFsyXSAmIGFubm90YXRpb24kcG9zID49IGFzLm51bWVyaWMoZG1yX2Nvb3JkWzNdKSAmIGFubm90YXRpb24kcG9zIDw9IGFzLm51bWVyaWMoZG1yX2Nvb3JkWzRdKSwgXSkKICByZXMgPC0gbGltbWFfcmVzW2NwZ3Msb249YygiSUQiPSJOYW1lIiksbm9tYXRjaD0wIF0KICBkbXJfMSA8LSBhcy5kYXRhLmZyYW1lKHJlc1shaXMubmEocmVzJGxvZ0ZDKSwgXSkKICBkbXJfbWV0aHkgPC0gcmVzaGFwZTI6Om1lbHQobHVtaTo6bTJiZXRhKG12YWx1ZXNbZG1yXzEkSUQsIF0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgdG9fcGxvdCA8LSBtZXJnZShkbXJfMSwgZG1yX21ldGh5LCBieS54ID0gIklEIiwgYnkueSA9ICJWYXIxIikKICB0b19wbG90JERNUiA8LSBkbXIKICB0b19wbG90Cn0KZ2V0X2Rtcl9yZXMgPC0gZnVuY3Rpb24oZG1yLCBsaW1tYV9yZXMpIHsKICBkbXJfY29vcmQgPC0gc3RyX21hdGNoX2FsbChhcy5jaGFyYWN0ZXIoZG1yKSwgIihjaHIuKik6KFswLTldKiktKFswLTldKikiKVtbMV1dCiAgY3BncyA8LSBhbm5vdGF0aW9uW2Fubm90YXRpb24kY2hyID09IGRtcl9jb29yZFsyXSAmIGFubm90YXRpb24kcG9zID49IGFzLm51bWVyaWMoZG1yX2Nvb3JkWzNdKSAmIGFubm90YXRpb24kcG9zIDw9IGFzLm51bWVyaWMoZG1yX2Nvb3JkWzRdKSwgXQogIHJlcyA8LSBjYmluZChjcGdzLCBsaW1tYV9yZXNbY3BncyROYW1lLCBdKQogIHJlcyRETVIgPC0gZG1yCiAgcmV0dXJuKHJlcykKfQpwbG90X2RtcnMgPC0gZnVuY3Rpb24oZG1yX3JlcyxsaW1tYV9yZXMscHJzX21hdCwgbXZhbHVlcywgY2FzZV9jb250cm9sKSB7CiAgdG9fcGxvdCA8LSByYmluZGxpc3QobGFwcGx5KGRtcl9yZXMkY29vcmQsIGZ1bmN0aW9uKGRtcikgZ2V0X2Rtcl9lZmZlY3RzKGRtciwgbGltbWFfcmVzLG12YWx1ZXMpKSkgJT4lCiAgICBtdXRhdGUoU0NPUkUxX0FWRyA9IHNjYWxlKHByc19tYXRbbWF0Y2goVmFyMixJRHMkSUlEKSxgUHRfNWUtMDhgXSksUEQgPSBQRFttYXRjaChWYXIyLElJRCldJFBEKSAlPiUKICAgIGZpbHRlcighaXMubmEoU0NPUkUxX0FWRykpCiAgZm9yKGN1cl9kbXIgaW4gdW5pcXVlKHRvX3Bsb3QkRE1SKSl7CiAgICBjdXJfcGxvdCA8LSB0b19wbG90W0RNUiA9PSBjdXJfZG1yXQogICAgcDEgPC0gZ2dwbG90KGN1cl9wbG90ICwgYWVzKHBvcywgdmFsdWUsIGNvbG9yID0gU0NPUkUxX0FWRykpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gcmV2KGNhc2VfY29udHJvbClbMV0sIGhpZ2ggPSByZXYoY2FzZV9jb250cm9sKVsyXSkgKwogICAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgICBsYWJzKHRpdGxlID0gdW5pcXVlKGN1cl9wbG90JERNUikseD0iUE9TIix5PWJxdW90ZSgiTWV0aHlsYXRpb24ifmJldGEpLGNvbG9yID0gIk5vcm1hbGl6ZWQgUEQgUFJTIikrCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQogICAgcDIgPC0gZ2dwbG90KGN1cl9wbG90ICU+JSBtdXRhdGUoUEQgPSBpZmVsc2UoUEQgPT0gMSwgIkNBU0UiLCAiQ09OVFJPTCIpKSwgYWVzKGZhY3Rvcihwb3MpLCB2YWx1ZSwgY29sb3IgPSBQRCkpICsKICAgICAgZ2VvbV9ib3hwbG90KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC43NSkpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNhc2VfY29udHJvbCkgKwogICAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gUEQpLCBmdW4gPSBtZWFuLCBnZW9tID0gImxpbmUiKSArCiAgICAgIGxhYnModGl0bGUgPSB1bmlxdWUoY3VyX3Bsb3QkRE1SKSx4PSJQT1MiLHk9YnF1b3RlKCJNZXRoeWxhdGlvbiJ+YmV0YSksY29sb3IgPSAiUEQgc3RhdHVzIikgKwogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKICAgIHByaW50KHAxKQogICAgcHJpbnQocDIpCiAgfQp9CgpwbG90X2RtcnMoZG1yX2Nyb3NzLCBwcnNfYW5ub3QsIHByc19tYXQsbXZhbHVlcywgcmV2KGMoImdyYXk4MCIsICJncmF5NDAiKSkpCnBsb3RfZG1ycyhkbXJfbWFsZXMscHJzX2Fubm90X21hbGUscHJzX21hdF9tYWxlLCBtdmFsdWVzX21hbGUscmV2KGMoImxpZ2h0IGJsdWUiLCAibGlnaHRibHVlNCIpKSkKcGxvdF9kbXJzKGRtcl9mZW1hbGUsIHByc19hbm5vdF9mZW1hbGUsIHByc19tYXRfZmVtYWxlLCBtdmFsdWVzX2ZlbWFsZSxyZXYoYygibGlnaHRwaW5rIiwgImxpZ2h0cGluazQiKSkpCmBgYAoKCmBgYHtyfQpkbXJfY3Jvc3MKZG1yX21hbGVzCmRtcl9mZW1hbGUKc2F2ZShsaXN0PWMoImRtcl9jcm9zcyIsImRtcl9tYWxlcyIsImRtcl9mZW1hbGUiKSxmaWxlPSJwcnNfZG1yX25hbGxzLlJEYXRhIikKYGBgCg==